package gitbucket.core.service

import gitbucket.core.model.{WebHook, RepositoryWebHook}
import org.scalatest.funsuite.AnyFunSuite
import gitbucket.core.model.WebHookContentType

class WebHookServiceSpec extends AnyFunSuite with ServiceSpecBase {
  lazy val service = new WebHookPullRequestService
    with AccountService
    with ActivityService
    with RepositoryService
    with MergeService
    with PullRequestService
    with IssuesService
    with CommitsService
    with LabelsService
    with MilestonesService
    with PrioritiesService
    with WebHookPullRequestReviewCommentService
    with RequestCache

  test("WebHookPullRequestService.getPullRequestsByRequestForWebhook") {
    withTestDB { implicit session =>
      val user1 = generateNewUserWithDBRepository("user1", "repo1")
      val user2 = generateNewUserWithDBRepository("user2", "repo2")
      val user3 = generateNewUserWithDBRepository("user3", "repo3")
      val issueUser = user("root")
      val (issue1, pullreq1) = generateNewPullRequest("user1/repo1/master1", "user2/repo2/master2", loginUser = "root")
      val (issue3, pullreq3) = generateNewPullRequest("user3/repo3/master3", "user2/repo2/master2", loginUser = "root")
      val (issue32, pullreq32) =
        generateNewPullRequest("user3/repo3/master32", "user2/repo2/master2", loginUser = "root")
      generateNewPullRequest("user2/repo2/master2", "user1/repo1/master2", loginUser = "root")
      service.addWebHook("user1", "repo1", "webhook1-1", Set(WebHook.PullRequest), WebHookContentType.FORM, Some("key"))
      service.addWebHook("user1", "repo1", "webhook1-2", Set(WebHook.PullRequest), WebHookContentType.FORM, Some("key"))
      service.addWebHook("user2", "repo2", "webhook2-1", Set(WebHook.PullRequest), WebHookContentType.FORM, Some("key"))
      service.addWebHook("user2", "repo2", "webhook2-2", Set(WebHook.PullRequest), WebHookContentType.FORM, Some("key"))
      service.addWebHook("user3", "repo3", "webhook3-1", Set(WebHook.PullRequest), WebHookContentType.FORM, Some("key"))
      service.addWebHook("user3", "repo3", "webhook3-2", Set(WebHook.PullRequest), WebHookContentType.FORM, Some("key"))

      assert(service.getPullRequestsByRequestForWebhook("user1", "repo1", "master1") == Map.empty)

      val r = service.getPullRequestsByRequestForWebhook("user2", "repo2", "master2").view.mapValues(_.map(_.url).toSet)

      assert(r.size == 3)
      assert(r((issue1, issueUser, pullreq1, user1, user2)) == Set("webhook1-1", "webhook1-2"))
      assert(r((issue3, issueUser, pullreq3, user3, user2)) == Set("webhook3-1", "webhook3-2"))
      assert(r((issue32, issueUser, pullreq32, user3, user2)) == Set("webhook3-1", "webhook3-2"))

      // when closed, it not founds.
      service.updateClosed("user1", "repo1", issue1.issueId, true)

      val r2 =
        service.getPullRequestsByRequestForWebhook("user2", "repo2", "master2").view.mapValues(_.map(_.url).toSet)
      assert(r2.size == 2)
      assert(r2((issue3, issueUser, pullreq3, user3, user2)) == Set("webhook3-1", "webhook3-2"))
      assert(r2((issue32, issueUser, pullreq32, user3, user2)) == Set("webhook3-1", "webhook3-2"))
    }
  }

  test("add and get and update and delete") {
    withTestDB { implicit session =>
      val user1 = generateNewUserWithDBRepository("user1", "repo1")
      val formType = WebHookContentType.FORM
      val jsonType = WebHookContentType.JSON
      service.addWebHook("user1", "repo1", "http://example.com", Set(WebHook.PullRequest), formType, Some("key"))
      assert(
        service.getWebHooks("user1", "repo1") == List(
          (
            RepositoryWebHook("user1", "repo1", 1, "http://example.com", formType, Some("key")),
            Set(WebHook.PullRequest)
          )
        )
      )
      assert(
        service.getWebHook("user1", "repo1", "http://example.com") == Some(
          (
            RepositoryWebHook("user1", "repo1", 1, "http://example.com", formType, Some("key")),
            Set(WebHook.PullRequest)
          )
        )
      )
      assert(
        service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == List(
          (RepositoryWebHook("user1", "repo1", 1, "http://example.com", formType, Some("key")))
        )
      )
      assert(service.getWebHooksByEvent("user1", "repo1", WebHook.Push) == Nil)
      assert(service.getWebHook("user1", "repo1", "http://example.com2") == None)
      assert(service.getWebHook("user2", "repo1", "http://example.com") == None)
      assert(service.getWebHook("user1", "repo2", "http://example.com") == None)
      service.updateWebHook(
        "user1",
        "repo1",
        "http://example.com",
        Set(WebHook.Push, WebHook.Issues),
        jsonType,
        Some("key")
      )
      assert(
        service.getWebHook("user1", "repo1", "http://example.com") == Some(
          (
            RepositoryWebHook("user1", "repo1", 1, "http://example.com", jsonType, Some("key")),
            Set(WebHook.Push, WebHook.Issues)
          )
        )
      )
      assert(service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == Nil)
      assert(
        service.getWebHooksByEvent("user1", "repo1", WebHook.Push) == List(
          (RepositoryWebHook("user1", "repo1", 1, "http://example.com", jsonType, Some("key")))
        )
      )
      service.deleteWebHook("user1", "repo1", "http://example.com")
      assert(service.getWebHook("user1", "repo1", "http://example.com") == None)
    }
  }

  test("getWebHooks, getWebHooksByEvent") {
    withTestDB { implicit session =>
      val user1 = generateNewUserWithDBRepository("user1", "repo1")
      val ctype = WebHookContentType.FORM
      service.addWebHook("user1", "repo1", "http://example.com/1", Set(WebHook.PullRequest), ctype, Some("key"))
      service.addWebHook("user1", "repo1", "http://example.com/2", Set(WebHook.Push), ctype, Some("key"))
      service.addWebHook(
        "user1",
        "repo1",
        "http://example.com/3",
        Set(WebHook.PullRequest, WebHook.Push),
        ctype,
        Some("key")
      )
      assert(
        service.getWebHooks("user1", "repo1") == List(
          RepositoryWebHook("user1", "repo1", 1, "http://example.com/1", ctype, Some("key")) -> Set(
            WebHook.PullRequest
          ),
          RepositoryWebHook("user1", "repo1", 2, "http://example.com/2", ctype, Some("key")) -> Set(WebHook.Push),
          RepositoryWebHook("user1", "repo1", 3, "http://example.com/3", ctype, Some("key")) -> Set(
            WebHook.PullRequest,
            WebHook.Push
          )
        )
      )
      assert(
        service.getWebHooksByEvent("user1", "repo1", WebHook.PullRequest) == List(
          RepositoryWebHook("user1", "repo1", 1, "http://example.com/1", ctype, Some("key")),
          RepositoryWebHook("user1", "repo1", 3, "http://example.com/3", ctype, Some("key"))
        )
      )
    }
  }
}
